import 'dart:async';
import 'dart:io';
import 'dart:isolate';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_application/app/app.dart';
import 'package:flutter_application/utils/queue_util.dart';
import 'package:isolates/isolates.dart';

class ThreadModelPage extends StatefulWidget {
  const ThreadModelPage({super.key});

  @override
  State<ThreadModelPage> createState() => _ThreadModelPageState();
}

class _ThreadModelPageState extends State<ThreadModelPage> {
  // 全局可用的 loadBalancer
  late LoadBalancer loadBalancer;

  int _count = 0;

  @override
  void initState() {
    super.initState();
    initBalancer();
  }

  threadLog(msg) {
    debugPrint('【thread】$msg');
  }

  initBalancer() async {
    // 线程数量
    loadBalancer = await LoadBalancer.create(2, IsolateRunner.spawn);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('线程模型'),
        ),
        body: SingleChildScrollView(
          child: Center(
              child: Column(children: [
            const Text('1、Event Loop机制'),
            Image.asset(
              App.imagePath('event_loop_1.png'),
            ),
            const Text('2、异步任务'),
            Image.asset(
              App.imagePath('event_loop.png'),
            ),
            ElevatedButton(
                onPressed: _eventLoopMethod,
                child: const Text('Event Loop 机制')),
            const SizedBox(
              width: 100,
              height: 100,
              child: CircularProgressIndicator(),
            ),
            Text('大量计算会卡顿 =》${_count.toString()}'),
            ElevatedButton(onPressed: _event, child: const Text('耗时操作会卡顿')),
            ElevatedButton(
                onPressed: _isolateEvent, child: const Text('isolate')),
            ElevatedButton(
                onPressed: _isolateEvent2, child: const Text('compute')),
            ElevatedButton(
                onPressed: _isolateEvent3,
                child: const Text('LoadBalancer线程池')),
            ElevatedButton(onPressed: _taskQueue, child: const Text('任务队列')),
            ElevatedButton(
                onPressed: _taskConcurrency, child: const Text('任务并发')),
            const SizedBox(
              height: 100,
            )
          ])),
        ));
  }

  _eventLoopMethod() {
    Future(() => threadLog('3、f1（第一个异步任务）')); // 声明一个匿名 Future
    Future fx = Future(() => null); // 声明 Future fx，其执行体为 null

    // 声明一个匿名 Future，并注册了两个 then。在第一个 then 回调里启动了一个微任务
    Future(() => threadLog('5、f2（异步任务）')).then((_) {
      threadLog('6、f3（then之后执行）');
      scheduleMicrotask(() => threadLog('8、f4（下一个事件循环）'));
    }).then((_) => threadLog('7、f5（then之后执行）'));

    // 声明了一个匿名 Future，并注册了两个 then。第一个 then 是一个 Future
    Future(() => threadLog('9、f6'))
        .then((_) => Future(() => threadLog('11、f7（异步放到下一个事件循环）')))
        .then((_) => threadLog('12、f8'));

    // 声明了一个匿名 Future
    Future(() => threadLog('10、f9'));

    // 往执行体为 null 的 fx 注册了了一个 then
    fx.then((_) => threadLog('4、f10（微任务队列）'));

    // 启动一个微任务
    scheduleMicrotask(() => threadLog('2、f11（微任务）'));
    threadLog('1、f12（同步任务）');
  }

  Isolate? isolate;

  void sendMsg(SendPort sendPort) {
    sendPort.send('hellow wrold');
  }

  _event() {
    //1、耗时操作，会感觉到卡顿
    _count = countEvent(1000000000);
    setState(() {});
  }

  _isolateEvent() async {
    //2、放到Isolate单独线程
    createIsolateCountEvent(1000000000);
  }

  _isolateEvent2() async {
    //3、内置函数compute
    _count = await computeCountEven(1000000000);
    setState(() {});
  }

  _isolateEvent3() async {
    //4、使用 LoadBalancer 执行任务
    // isolates: 3.0.3+8
    _count = await loadBalancer.run<int, int>(countEvent, 1000000000);
    setState(() {});
  }

  /*
  一、Isolate原生实现
  1、创建一个ReceivePort(),是我们当前线程用来接收发送消息的工具
  2、通过Isolate.spawn(entryPoint,message)创建另一个线程
     spawn的参数entryPoint,需要是静态方法,或者是顶层函数,创建时message一般传当前ReceivePort对应的SendPort
  3、编写entryPoint方法,参数类型需跟第二步中的参数一致,然后在方法内创建新线程的ReceivePort
  4、在entryPoint方法中,用传入的SendPort参数,把新线程的ReceivePort的SendPort返回出去.
  两边的ReceivePort都实现listen方法
  5、至此,通道就建立好了,可以互相发送,接受消息了
  */

  static var staticVar = 1;
  //先改了静态变量为3,新线程内再操作,输出的值.证明了isolate的数据有隔离性.

  createIsolateCountEvent(int num) async {
    //1、创建当前isolateA的接收端口
    var aReceived = ReceivePort();

    staticVar = 3;

    //2、创建新的isolateB，并且把当前A的端口带过去
    var newIsolate =
        await Isolate.spawn(createNewIsolateCountEven, aReceived.sendPort);
    aReceived.listen((message) {
      if (message is SendPort) {
        //5、拿到发送端口可以发送消息了
        message.send(num);
      } else {
        _count = message;
        setState(() {});

        threadLog('a $staticVar');

        //不需要时，释放isolate
        newIsolate.kill();
      }
    });
  }

  //运行再isolateB的方法
  static void createNewIsolateCountEven(SendPort aPort) {
    //3、创建isolateB的端口
    var bReceived = ReceivePort();
    //4、把isolateB的发送端口带过去
    aPort.send(bReceived.sendPort);
    bReceived.listen((message) {
      staticVar++;

      print('b $staticVar');

      //6、监听到消息可以做处理了
      //调用static方法或者top-level方法
      var res = countEvent(message);
      aPort.send(res);
    });
  }

  // 大量计算
  static int countEvent(int num) {
    int count = 0;
    while (num > 0) {
      if (num % 2 == 0) {
        count++;
      }
      num--;
    }
    return count;
  }

  /*
   二、内置函数compute
   使用compute创建的isolate是一次性的,用完就释放了
   不适合频繁使用,容易内存抖动或造成oom
   */
  Future<int> computeCountEven(int num) async {
    return await compute(countEvent, num);
  }

  _taskQueue() {
    var queue = QueueUtil.get('taskQueue');
    for (int i = 0; i < 10; i++) {
      queue.addTask(() async {
        var res =
            await Future.delayed(const Duration(seconds: 1)).then((value) {
          return '任务结束：$i';
        });
        threadLog(res);
      });
      queue.finishCallBack(() {
        threadLog('全部结束了');
      });
    }
  }

  _taskConcurrency() async {
    // 方式1：compute
    // compute1("c1");
    // compute2("c2");

    // 方式2：
    for (int i = 0; i < 10; i++) {
      balancer('task $i');
    }

  }

  //方式1：compute
  compute1(String c1) async {
    await compute(printTask, c1);
  }

  compute2(String c2) async {
    await compute(printTask, c2);
  }

  //定义两个耗时方法，每隔2秒打印一次，总共打印50次
  static void printTask(String p1) {
    for (int i = 0; i < 10; i++) {
      sleep(const Duration(seconds: 1));
      print(p1);
    }
  }

  //方式2：compute
  balancer(msg) async {
    await loadBalancer.run<void, String>(printTask, msg);
  }
}
